﻿using DatabaseLib;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Xml;
using SysTime = System.Timers;
using ADODB;
using System.Xml.Serialization;
using System.Data.SqlTypes;

namespace EnergyBilling
{
    public partial class BillingService : ServiceBase
    {
        public BillingService()
        {
            InitializeComponent();
            if (!System.Diagnostics.EventLog.SourceExists("BillingEnergySource"))
            {
                System.Diagnostics.EventLog.CreateEventSource(
                    "BillingEnergySource", "BillingEnergyLog");
            }
            BillingEventLog.Source = "BillingEnergySource";
            BillingEventLog.Log = "BillingEnergyLog";

        }

        protected override void OnStart(string[] args)
        {
            BillingEventLog.WriteEntry(Properties.Resources.ServerStarted);
            try
            {
                _serverName = args[0];
                _dbName = args[1];
                _isWindowsAuthentification = Convert.ToBoolean(args[2], CultureInfo.InvariantCulture);
                _login = args[3];
                _password = args[4];
                _pathToCatalog = args[5];
                _pathToArchive = args[6];
                _interval = Convert.ToInt32(args[7], CultureInfo.InvariantCulture) * 6000;
                _isArchived = Convert.ToBoolean(args[8], CultureInfo.InvariantCulture);

                BillingEventLog.WriteEntry(String.Format("Start with argument: ServerName: {0}, DbName: {1}, IsWindowsAuthentification: {2}, Login: {3}, PathToCatalog: {4}, PathToArchive: {5}, Interval: {6}, IsArchived: {7}"
                    , args[0], args[1], args[2], args[3], args[5], args[6], args[7], args[8]));

                _timer = new SysTime.Timer(_interval);
                _timer.Elapsed += timer_Elapsed;
                _timer.Enabled = true;
            }
            catch (Exception err)
            {
                BillingEventLog.WriteEntry(err.Message, EventLogEntryType.Error);
            }
        }
        private void timer_Elapsed(object sender, SysTime.ElapsedEventArgs e)
        {
            try
            {
                string[] files = Directory.GetFiles(_pathToCatalog);

                if (files.Count() > 0)
                {
                    foreach (string item in files)
                    {
                        // Полученный файл передается на сервер
                        if (LoadFileToServer(item))
                        {
                            // Загруженный файл помещается в архив
                            if (_isArchived)
                                Compress(item, _pathToArchive);
                            else
                                File.Copy(item, Path.Combine(_pathToArchive, Path.GetFileName(item)));
                            
                            File.Delete(item);
                            BillingEventLog.WriteEntry(String.Format(Properties.Resources.FileProccessed, Path.GetFileName(item)));
                        }
                        else // Файл помещается в каталог не записанных файлов
                        {
                            DirectoryInfo di = new DirectoryInfo(_pathToCatalog + Properties.Resources.UnCheckedFiles);
                            if (!di.Exists)
                                di.Create();
                            
                            Compress(item, _pathToCatalog + Properties.Resources.UnCheckedFiles);
                            File.Delete(item);

                            BillingEventLog.WriteEntry(String.Format(Properties.Resources.FileUnProccessed, Path.GetFileName(item)));
                        }
                    }
                }
            }
            catch (Exception err)
            {
                BillingEventLog.WriteEntry(err.Message);
            }
        }
        protected override void OnStop()
        {
            BillingEventLog.WriteEntry(Properties.Resources.ServerStoped);
        }

        private void Compress(string  pathToCatalog, string pathToArch)
        {
            try
            {
                using (FileStream originalFileStream = new FileStream(pathToCatalog, FileMode.Open))
                {
                    using (ZipOutputStream s = new ZipOutputStream(File.Create(Path.Combine(pathToArch, Path.GetFileName(pathToCatalog)) + ".zip")))
                    {
                        s.SetLevel(7); // 0 - store only to 9 - means best compression
                        byte[] buffer = new byte[originalFileStream.Length];
                        int count = originalFileStream.Read(buffer, 0, buffer.Length);

                        ZipEntry entry = new ZipEntry(Path.GetFileName(pathToCatalog));

                        entry.DateTime = DateTime.Now;
                        s.PutNextEntry(entry);
                        s.Write(buffer, 0, buffer.Length);
                    }
                }
            }
            catch (Exception err)
            {
                BillingEventLog.WriteEntry(err.Message, EventLogEntryType.Error);
            }
        }
        private bool LoadFileToServer(string pathFile)
        {
            try
            {
                XmlDocument xmlObject = new XmlDocument();
                xmlObject.Load(pathFile);

                using (var outputStream = new MemoryStream())
                {
                    using (var writer = XmlWriter.Create(outputStream))
                    {
                        var serializer = new XmlSerializer(xmlObject.GetType());
                        serializer.Serialize(writer, xmlObject);
                    }

                    SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder()
                    {
                        DataSource = _serverName,
                        InitialCatalog = _dbName,
                        UserID = _login,
                        Password = _password,
                        IntegratedSecurity = _isWindowsAuthentification
                    };

                    outputStream.Position = 0;
                    using (var conn = new SqlConnection(builder.ConnectionString))
                    {
                        conn.Open();

                        using (var cmd = new SqlCommand(Properties.Resources.SQL_InsertXML, conn))
                        {
                            using (var reader = XmlReader.Create(outputStream))
                            {
                                var xml = new SqlXml(reader);
                                cmd.Parameters.Clear();
                                cmd.Parameters.AddWithValue(Properties.Resources.SQL_InsertParamName, xml);
                                cmd.ExecuteNonQuery();
                            }
                        }
                    }
                }
                return true;
            }
            catch (Exception err)
            {
                BillingEventLog.WriteEntry(err.Message, EventLogEntryType.Error);
                return false;
            }

        }

        #region Fields

        private SysTime.Timer _timer;
        private string _serverName;
        private string _dbName;
        private bool _isWindowsAuthentification;
        private string _login;
        private string _password;
        private string _pathToCatalog;
        private string _pathToArchive;
        private int _interval;
        private bool _isArchived;

        #endregion

    }
}
